package gateway

import (
	"fmt"
	"io"
	"net"
	"sync"
	"tinp/common"
	"tinp/mylog"
)

type Listener struct {
	closeOnce   sync.Once
	close       chan struct{}
	tcpListener net.Listener
	sessionMgr  *SessionManager
	pp          *common.ProxyProtocol
}

func NewListener(pp *common.ProxyProtocol, manager *SessionManager) *Listener {
	return &Listener{
		sessionMgr: manager,
		pp:         pp,
		close:      make(chan struct{}),
	}
}
func (l *Listener) ListenAndServe() error {
	return l.ListenAndServeTCP()
}
func (l *Listener) ListenAndServeTCP() error {
	listenAddr := fmt.Sprintf("%s:%d", l.pp.ListenIp, l.pp.ListenPort)
	listen, err := net.Listen("tcp", listenAddr)
	if err != nil {
		return err
	}
	defer listen.Close()
	for {
		conn, err := listen.Accept()
		if err != nil && err == io.EOF {
			return err
		}
		go l.handleConn(conn)
	}
}
func (l *Listener) handleConn(conn net.Conn) {
	// 断开连接
	defer conn.Close()
	// 查询Session
	tunnelConn := l.sessionMgr.GetSessionByClientId(l.pp.ClientId)
	if tunnelConn == nil {
		return
	}
	defer tunnelConn.Close()
	// 封装 proxyProtocol
	body, err := l.pp.Encode()
	if err != nil {
		mylog.Logger.Warnf("encode pp fail： %v", err)
		return
	}
	_, err = tunnelConn.Write(body)
	if err != nil {
		mylog.Logger.Warnf("write pp body fail： %v", err)
		return
	}
	go func() {
		defer func() {
			tunnelConn.Close()
			conn.Close()
		}()
		io.Copy(tunnelConn, conn)
	}()
	// 双向数据拷贝
	io.Copy(conn, tunnelConn)
}
func (l *Listener) Close() {
	l.closeOnce.Do(func() {
		close(l.close)
		if l.tcpListener != nil {
			l.tcpListener.Close()
		} else {

		}
	})
}
